{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0",
   "metadata": {},
   "source": [
    "[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/gee-community/geemap/blob/master/docs/workshops/GEE_Workshop_2025.ipynb)\n",
    "\n",
    "**Geospatial Data Analysis and Visualization with Earth Engine**\n",
    "\n",
    "-   Notebook: <https://geemap.org/workshops/GEE_Workshop_2025>\n",
    "-   Earth Engine: <https://earthengine.google.com>\n",
    "-   Geemap: <https://geemap.org>\n",
    "\n",
    "## Introduction\n",
    "\n",
    "This notebook contains the materials for the workshop **Geospatial Data Analysis and Visualization with Earth Engine** at the 第八届地球空间大数据与云计算研讨会.\n",
    "\n",
    "### Agenda\n",
    "\n",
    "This workshop covers the following topics:\n",
    "- Colab setup\n",
    "- Data visualization in 3D\n",
    "- Creating timelapse animations\n",
    "- Exporting Earth Engine data\n",
    "- Charts\n",
    "\n",
    "\n",
    "### Prerequisites\n",
    "\n",
    "-   To use geemap and the Earth Engine Python API, you must [register](https://code.earthengine.google.com/register) for an Earth Engine account and follow the instructions [here](https://docs.google.com/document/d/1ZGSmrNm6_baqd8CHt33kIBWOlvkh-HLr46bODgJN1h0/edit?usp=sharing) to create a Cloud Project. Earth Engine is free for [noncommercial and research use](https://earthengine.google.com/noncommercial). To test whether you can use authenticate the Earth Engine Python API, please run [this notebook](https://colab.research.google.com/github/gee-community/geemap/blob/master/docs/notebooks/geemap_colab.ipynb) on Google Colab.\n",
    "\n",
    "## Technical requirements\n",
    "\n",
    "### Install packages\n",
    "\n",
    "```bash\n",
    "conda create -n gee python=3.12\n",
    "conda activate gee\n",
    "conda install -c conda-forge mamba\n",
    "mamba install -c conda-forge geemap leafmap maplibre\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# %pip install \"geemap[workshop]\" leafmap maplibre"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2",
   "metadata": {},
   "source": [
    "### Import libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3",
   "metadata": {},
   "outputs": [],
   "source": [
    "import ee\n",
    "import geemap\n",
    "import leafmap.maplibregl as leafmap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4",
   "metadata": {},
   "outputs": [],
   "source": [
    "ee.Authenticate()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5",
   "metadata": {},
   "outputs": [],
   "source": [
    "ee.Initialize(project=\"YOUR-PROJECT-ID\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6",
   "metadata": {},
   "source": [
    "## Colab setup\n",
    "\n",
    "Uncomment the following line to get the Earth Engine authorization token. Please treat your token with care and don't share it with anyone. Copy the token to the clipboard."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# geemap.get_ee_token()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8",
   "metadata": {},
   "source": [
    "1. Open your Google Colab notebook and click on the `secrets` tab.\n",
    "2. Create a new secret with the name `EARTHENGINE_TOKEN`.\n",
    "3. Paste the content from the clipboard into the `Value` input box of the created secret.\n",
    "4. Toggle the button on the left to allow notebook access to the secret.\n",
    "\n",
    "![](https://i.imgur.com/Z9R08uU.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9",
   "metadata": {},
   "source": [
    "## Data Visualization in 3D\n",
    "\n",
    "### Globe projection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "10",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(center=[-100, 40], zoom=3, style=\"liberty\")\n",
    "m.add_globe_control()\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "11",
   "metadata": {},
   "source": [
    "### Overture buildings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "12",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(center=[-100, 40], zoom=3, style=\"positron\", projection=\"globe\")\n",
    "m.add_overture_3d_buildings()\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13",
   "metadata": {},
   "source": [
    "### Add basemaps"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(center=[-100, 40], zoom=3, style=\"positron\", projection=\"globe\")\n",
    "m.add_basemap(\"Esri.WorldImagery\")\n",
    "m.add_overture_3d_buildings()\n",
    "m.add_layer_control()\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15",
   "metadata": {},
   "source": [
    "### Visualize Earth Engine data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16",
   "metadata": {},
   "source": [
    "To use the `3d-terrain` basemap, you will need an [API key](https://docs.maptiler.com/cloud/api/authentication-key/) from [MapTiler](https://www.maptiler.com/cloud/). Once you have the API key, you can uncomment the following code block and replace `YOUR_API_KEY` with your actual API key. Then, run the code block code to set the API key as an environment variable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "17",
   "metadata": {},
   "outputs": [],
   "source": [
    "# import os\n",
    "# os.environ[\"MAPTILER_KEY\"] = \"YOUR_API_KEY\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(style=\"3d-terrain\", projection=\"globe\")\n",
    "m.add_ee_layer(asset_id=\"ESA/WorldCover/v200\", opacity=0.5)\n",
    "m.add_legend(builtin_legend=\"ESA_WorldCover\", title=\"ESA Landcover\")\n",
    "m.add_overture_3d_buildings()\n",
    "m.add_layer_control()\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "19",
   "metadata": {},
   "outputs": [],
   "source": [
    "m.layer_interact()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20",
   "metadata": {},
   "source": [
    "Land cover data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "21",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(style=\"3d-terrain\", projection=\"globe\")\n",
    "dataset = ee.ImageCollection(\"ESA/WorldCover/v200\").first()\n",
    "vis_params = {\"bands\": [\"Map\"]}\n",
    "m.add_ee_layer(dataset, vis_params, name=\"ESA Worldcover\", opacity=0.5)\n",
    "m.add_legend(builtin_legend=\"ESA_WorldCover\", title=\"ESA Landcover\")\n",
    "m.add_layer_control()\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22",
   "metadata": {},
   "source": [
    "Night time light data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "23",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = leafmap.Map(style=\"darkmatter\", projection=\"globe\")\n",
    "dataset = ee.ImageCollection(\"NOAA/VIIRS/DNB/ANNUAL_V22\").filter(\n",
    "    ee.Filter.date(\"2022-01-01\", \"2023-01-01\")\n",
    ")\n",
    "nighttime = dataset.select(\"maximum\")\n",
    "nighttimeVis = {\"min\": 0.0, \"max\": 60.0}\n",
    "m.add_ee_layer(nighttime, nighttimeVis, name=\"Nighttime\")\n",
    "\n",
    "countries = ee.FeatureCollection(\"USDOS/LSIB_SIMPLE/2017\")\n",
    "styleParams = {\n",
    "    \"fillColor\": \"00000000\",\n",
    "    \"color\": \"ff0000\",\n",
    "    \"width\": 1.0,\n",
    "}\n",
    "countries = countries.style(**styleParams)\n",
    "m.add_ee_layer(countries, {}, name=\"Country Boundaries\")\n",
    "m.add_layer_control()\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24",
   "metadata": {},
   "source": [
    "## Creating timelapse animations\n",
    "\n",
    "### Landsat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "25",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map(center=[22.95459, 113.94078], zoom=10)\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26",
   "metadata": {},
   "source": [
    "Pan and zoom the map to an area of interest. Use the drawing tools to draw a rectangle on the map. If no rectangle is drawn, the default rectangle shown below will be used."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "27",
   "metadata": {},
   "outputs": [],
   "source": [
    "m.user_roi_coords()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "28",
   "metadata": {},
   "outputs": [],
   "source": [
    "roi = m.user_roi\n",
    "if roi is None:\n",
    "    roi = ee.Geometry.BBox(113.5059, 22.6805, 114.2939, 23.1195)\n",
    "    m.add_layer(roi)\n",
    "    m.center_object(roi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "29",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.landsat_timelapse(\n",
    "    roi,\n",
    "    out_gif=\"Dongguan.gif\",\n",
    "    start_year=1986,\n",
    "    end_year=2025,\n",
    "    start_date=\"01-01\",\n",
    "    end_date=\"12-31\",\n",
    "    bands=[\"SWIR1\", \"NIR\", \"Red\"],\n",
    "    frames_per_second=5,\n",
    "    title=\"Landsat Timelapse\",\n",
    "    progress_bar_color=\"blue\",\n",
    "    mp4=True,\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "30",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map(center=[22.95459, 113.94078], zoom=10)\n",
    "m.add_gui(\"timelapse\")\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "31",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map()\n",
    "roi = ee.Geometry.BBox(113.6278, 22.639, 113.8983, 22.8024)\n",
    "m.add_layer(roi)\n",
    "m.center_object(roi)\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "32",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.landsat_timelapse(\n",
    "    roi,\n",
    "    out_gif=\"Donguan2.gif\",\n",
    "    start_year=1986,\n",
    "    end_year=2025,\n",
    "    start_date=\"01-01\",\n",
    "    end_date=\"12-31\",\n",
    "    bands=[\"SWIR1\", \"NIR\", \"Red\"],\n",
    "    frames_per_second=5,\n",
    "    title=\"Dongguan, China\",\n",
    "    font_color=\"red\",\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map()\n",
    "roi = ee.Geometry.BBox(113.8252, 22.1988, 114.0851, 22.3497)\n",
    "m.add_layer(roi)\n",
    "m.center_object(roi)\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "34",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.landsat_timelapse(\n",
    "    roi,\n",
    "    out_gif=\"hong_kong.gif\",\n",
    "    start_year=1990,\n",
    "    end_year=2022,\n",
    "    start_date=\"01-01\",\n",
    "    end_date=\"12-31\",\n",
    "    bands=[\"SWIR1\", \"NIR\", \"Red\"],\n",
    "    frames_per_second=3,\n",
    "    title=\"Hong Kong\",\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "35",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map()\n",
    "roi = ee.Geometry.BBox(-115.5541, 35.8044, -113.9035, 36.5581)\n",
    "m.add_layer(roi)\n",
    "m.center_object(roi)\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "36",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.landsat_timelapse(\n",
    "    roi,\n",
    "    out_gif=\"las_vegas.gif\",\n",
    "    start_year=1984,\n",
    "    end_year=2025,\n",
    "    bands=[\"NIR\", \"Red\", \"Green\"],\n",
    "    frames_per_second=5,\n",
    "    title=\"Las Vegas, NV\",\n",
    "    font_color=\"blue\",\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37",
   "metadata": {},
   "source": [
    "### MODIS\n",
    "\n",
    "MODIS vegetation indices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "38",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map()\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39",
   "metadata": {},
   "outputs": [],
   "source": [
    "roi = m.user_roi\n",
    "if roi is None:\n",
    "    roi = ee.Geometry.BBox(-18.6983, -36.1630, 52.2293, 38.1446)\n",
    "    m.add_layer(roi)\n",
    "    m.center_object(roi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.modis_ndvi_timelapse(\n",
    "    roi,\n",
    "    out_gif=\"ndvi.gif\",\n",
    "    data=\"Terra\",\n",
    "    band=\"NDVI\",\n",
    "    start_date=\"2000-01-01\",\n",
    "    end_date=\"2025-12-31\",\n",
    "    frames_per_second=3,\n",
    "    title=\"MODIS NDVI Timelapse\",\n",
    "    overlay_data=\"countries\",\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41",
   "metadata": {},
   "source": [
    "MODIS temperature"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "42",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map()\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "43",
   "metadata": {},
   "outputs": [],
   "source": [
    "roi = m.user_roi\n",
    "if roi is None:\n",
    "    roi = ee.Geometry.BBox(-171.21, -57.13, 177.53, 79.99)\n",
    "    m.add_layer(roi)\n",
    "    m.center_object(roi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "44",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.modis_ocean_color_timelapse(\n",
    "    satellite=\"Aqua\",\n",
    "    start_date=\"2018-01-01\",\n",
    "    end_date=\"2020-12-31\",\n",
    "    roi=roi,\n",
    "    frequency=\"month\",\n",
    "    out_gif=\"temperature.gif\",\n",
    "    overlay_data=\"continents\",\n",
    "    overlay_color=\"yellow\",\n",
    "    overlay_opacity=0.5,\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45",
   "metadata": {},
   "source": [
    "### GOES"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "46",
   "metadata": {},
   "outputs": [],
   "source": [
    "roi = ee.Geometry.BBox(167.1898, -28.5757, 202.6258, -12.4411)\n",
    "start_date = \"2022-01-15T03:00:00\"\n",
    "end_date = \"2022-01-15T07:00:00\"\n",
    "data = \"GOES-17\"\n",
    "scan = \"full_disk\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "47",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.goes_timelapse(\n",
    "    roi, \"goes.gif\", start_date, end_date, data, scan, framesPerSecond=5\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "48",
   "metadata": {},
   "outputs": [],
   "source": [
    "roi = ee.Geometry.BBox(-159.5954, 24.5178, -114.2438, 60.4088)\n",
    "start_date = \"2021-10-24T14:00:00\"\n",
    "end_date = \"2021-10-25T01:00:00\"\n",
    "data = \"GOES-17\"\n",
    "scan = \"full_disk\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.goes_timelapse(\n",
    "    roi, \"hurricane.gif\", start_date, end_date, data, scan, framesPerSecond=5\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50",
   "metadata": {},
   "outputs": [],
   "source": [
    "roi = ee.Geometry.BBox(-121.0034, 36.8488, -117.9052, 39.0490)\n",
    "start_date = \"2020-09-05T15:00:00\"\n",
    "end_date = \"2020-09-06T02:00:00\"\n",
    "data = \"GOES-17\"\n",
    "scan = \"full_disk\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "51",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.goes_fire_timelapse(\n",
    "    roi, \"fire.gif\", start_date, end_date, data, scan, framesPerSecond=5\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52",
   "metadata": {},
   "source": [
    "### NAIP"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map(center=[40, -100], zoom=4)\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54",
   "metadata": {},
   "outputs": [],
   "source": [
    "roi = m.user_roi\n",
    "if roi is None:\n",
    "    roi = ee.Geometry.BBox(-99.1019, 47.1274, -99.0334, 47.1562)\n",
    "    m.add_layer(roi)\n",
    "    m.center_object(roi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "55",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.naip_timelapse(\n",
    "    roi,\n",
    "    out_gif=\"naip.gif\",\n",
    "    bands=[\"N\", \"R\", \"G\"],\n",
    "    frames_per_second=3,\n",
    "    title=\"NAIP Timelapse\",\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56",
   "metadata": {},
   "source": [
    "### Sentinel-1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "57",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map()\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58",
   "metadata": {},
   "outputs": [],
   "source": [
    "roi = m.user_roi\n",
    "if roi is None:\n",
    "    roi = ee.Geometry.BBox(117.1132, 3.5227, 117.2214, 3.5843)\n",
    "    m.add_layer(roi)\n",
    "    m.center_object(roi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "59",
   "metadata": {},
   "outputs": [],
   "source": [
    "timelapse = geemap.sentinel1_timelapse(\n",
    "    roi,\n",
    "    out_gif=\"sentinel1.gif\",\n",
    "    start_year=2019,\n",
    "    end_year=2019,\n",
    "    start_date=\"04-01\",\n",
    "    end_date=\"08-01\",\n",
    "    bands=[\"VV\"],\n",
    "    frequency=\"day\",\n",
    "    vis_params={\"min\": -30, \"max\": 0},\n",
    "    palette=\"Greys\",\n",
    "    frames_per_second=3,\n",
    "    title=\"Sentinel-1 Timelapse\",\n",
    "    add_colorbar=True,\n",
    "    colorbar_bg_color=\"gray\",\n",
    ")\n",
    "geemap.show_image(timelapse)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60",
   "metadata": {},
   "source": [
    "## Exporting Earth Engine data\n",
    "\n",
    "### Exporting images\n",
    "\n",
    "Add a Landsat image to the map."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map()\n",
    "\n",
    "image = ee.Image(\"LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318\").select(\n",
    "    [\"B5\", \"B4\", \"B3\"]\n",
    ")\n",
    "\n",
    "vis_params = {\"min\": 0, \"max\": 0.5, \"gamma\": [0.95, 1.1, 1]}\n",
    "\n",
    "m.center_object(image)\n",
    "m.add_layer(image, vis_params, \"Landsat\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62",
   "metadata": {},
   "source": [
    "Add a rectangle to the map."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63",
   "metadata": {},
   "outputs": [],
   "source": [
    "region = ee.Geometry.BBox(-122.5955, 37.5339, -122.0982, 37.8252)\n",
    "fc = ee.FeatureCollection(region)\n",
    "style = {\"color\": \"ffff00ff\", \"fillColor\": \"00000000\"}\n",
    "m.add_layer(fc.style(**style), {}, \"ROI\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "64",
   "metadata": {},
   "source": [
    "To local drive"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "65",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_export_image(image, filename=\"landsat.tif\", scale=30, region=region)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66",
   "metadata": {},
   "source": [
    "Check image projection."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "67",
   "metadata": {},
   "outputs": [],
   "source": [
    "projection = image.select(0).projection().getInfo()\n",
    "projection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "68",
   "metadata": {},
   "outputs": [],
   "source": [
    "crs = projection[\"crs\"]\n",
    "crs_transform = projection[\"transform\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69",
   "metadata": {},
   "source": [
    "Specify region, crs, and crs_transform."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "70",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_export_image(\n",
    "    image,\n",
    "    filename=\"landsat_crs.tif\",\n",
    "    crs=crs,\n",
    "    crs_transform=crs_transform,\n",
    "    region=region,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71",
   "metadata": {},
   "source": [
    "To Google Drive"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "72",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_export_image_to_drive(\n",
    "    image, description=\"landsat\", folder=\"export\", region=region, scale=30\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "73",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.download_ee_image(image, \"landsat.tif\", scale=90)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74",
   "metadata": {},
   "source": [
    "### Exporting image collections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "75",
   "metadata": {},
   "outputs": [],
   "source": [
    "point = ee.Geometry.Point(-99.2222, 46.7816)\n",
    "collection = (\n",
    "    ee.ImageCollection(\"USDA/NAIP/DOQQ\")\n",
    "    .filterBounds(point)\n",
    "    .filterDate(\"2008-01-01\", \"2018-01-01\")\n",
    "    .filter(ee.Filter.listContains(\"system:band_names\", \"N\"))\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "76",
   "metadata": {},
   "outputs": [],
   "source": [
    "collection.aggregate_array(\"system:index\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "77",
   "metadata": {},
   "source": [
    "To local drive"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "78",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_export_image_collection(collection, out_dir=\".\", scale=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79",
   "metadata": {},
   "source": [
    "To Google Drive"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "80",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_export_image_collection_to_drive(collection, folder=\"export\", scale=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81",
   "metadata": {},
   "source": [
    "### Exporting feature collections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "82",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = geemap.Map()\n",
    "states = ee.FeatureCollection(\"TIGER/2018/States\")\n",
    "fc = states.filter(ee.Filter.eq(\"NAME\", \"Alaska\"))\n",
    "m.add_layer(fc, {}, \"Alaska\")\n",
    "m.center_object(fc, 4)\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83",
   "metadata": {},
   "source": [
    "To local drive"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "84",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_to_shp(fc, filename=\"Alaska.shp\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "85",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_export_vector(fc, filename=\"Alaska.shp\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "86",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_to_geojson(fc, filename=\"Alaska.geojson\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "87",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_to_csv(fc, filename=\"Alaska.csv\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "88",
   "metadata": {},
   "outputs": [],
   "source": [
    "gdf = geemap.ee_to_gdf(fc)\n",
    "gdf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "89",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = geemap.ee_to_df(fc)\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "90",
   "metadata": {},
   "source": [
    "To Google Drive"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "91",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_export_vector_to_drive(\n",
    "    fc, description=\"Alaska\", fileFormat=\"SHP\", folder=\"export\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92",
   "metadata": {},
   "source": [
    "## Charts \n",
    "\n",
    "### Feature and FeatureCollection\n",
    "\n",
    "#### Import libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "93",
   "metadata": {},
   "outputs": [],
   "source": [
    "import calendar\n",
    "from geemap import chart"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94",
   "metadata": {},
   "source": [
    "#### feature_by_feature\n",
    "\n",
    "Features are plotted along the x-axis, labeled by values of a selected property. Series are represented by adjacent columns defined by a list of property names whose values are plotted along the y-axis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "95",
   "metadata": {},
   "outputs": [],
   "source": [
    "ecoregions = ee.FeatureCollection(\"projects/google/charts_feature_example\")\n",
    "features = ecoregions.select(\"[0-9][0-9]_tmean|label\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "96",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_to_df(features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "97",
   "metadata": {},
   "outputs": [],
   "source": [
    "x_property = \"label\"\n",
    "y_properties = [str(x).zfill(2) + \"_tmean\" for x in range(1, 13)]\n",
    "\n",
    "labels = calendar.month_abbr[1:]  # a list of month labels, e.g. ['Jan', 'Feb', ...]\n",
    "\n",
    "colors = [\n",
    "    \"#604791\",\n",
    "    \"#1d6b99\",\n",
    "    \"#39a8a7\",\n",
    "    \"#0f8755\",\n",
    "    \"#76b349\",\n",
    "    \"#f0af07\",\n",
    "    \"#e37d05\",\n",
    "    \"#cf513e\",\n",
    "    \"#96356f\",\n",
    "    \"#724173\",\n",
    "    \"#9c4f97\",\n",
    "    \"#696969\",\n",
    "]\n",
    "title = \"Average Monthly Temperature by Ecoregion\"\n",
    "x_label = \"Ecoregion\"\n",
    "y_label = \"Temperature\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "98",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.feature_by_feature(\n",
    "    features,\n",
    "    x_property,\n",
    "    y_properties,\n",
    "    colors=colors,\n",
    "    labels=labels,\n",
    "    title=title,\n",
    "    x_label=x_label,\n",
    "    y_label=y_label,\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/MZa99Vf.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "100",
   "metadata": {},
   "source": [
    "#### feature.by_property"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "101",
   "metadata": {},
   "outputs": [],
   "source": [
    "ecoregions = ee.FeatureCollection(\"projects/google/charts_feature_example\")\n",
    "features = ecoregions.select(\"[0-9][0-9]_ppt|label\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "102",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_to_df(features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "103",
   "metadata": {},
   "outputs": [],
   "source": [
    "keys = [str(x).zfill(2) + \"_ppt\" for x in range(1, 13)]\n",
    "values = calendar.month_abbr[1:]  # a list of month labels, e.g. ['Jan', 'Feb', ...]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "104",
   "metadata": {},
   "outputs": [],
   "source": [
    "x_properties = dict(zip(keys, values))\n",
    "series_property = \"label\"\n",
    "title = \"Average Ecoregion Precipitation by Month\"\n",
    "colors = [\"#f0af07\", \"#0f8755\", \"#76b349\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "105",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.feature_by_property(\n",
    "    features,\n",
    "    x_properties,\n",
    "    series_property,\n",
    "    title=title,\n",
    "    colors=colors,\n",
    "    x_label=\"Month\",\n",
    "    y_label=\"Precipitation (mm)\",\n",
    "    legend_location=\"top-left\",\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "106",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/6RhuUc7.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "107",
   "metadata": {},
   "source": [
    "#### feature_groups"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "108",
   "metadata": {},
   "outputs": [],
   "source": [
    "ecoregions = ee.FeatureCollection(\"projects/google/charts_feature_example\")\n",
    "features = ecoregions.select(\"[0-9][0-9]_ppt|label\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "109",
   "metadata": {},
   "outputs": [],
   "source": [
    "features = ee.FeatureCollection(\"projects/google/charts_feature_example\")\n",
    "x_property = \"label\"\n",
    "y_property = \"01_tmean\"\n",
    "series_property = \"warm\"\n",
    "title = \"Average January Temperature by Ecoregion\"\n",
    "colors = [\"#cf513e\", \"#1d6b99\"]\n",
    "labels = [\"Warm\", \"Cold\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "110",
   "metadata": {},
   "outputs": [],
   "source": [
    "chart.feature_groups(\n",
    "    features,\n",
    "    x_property,\n",
    "    y_property,\n",
    "    series_property,\n",
    "    title=title,\n",
    "    colors=colors,\n",
    "    x_label=\"Ecoregion\",\n",
    "    y_label=\"January Temperature (°C)\",\n",
    "    legend_location=\"top-right\",\n",
    "    labels=labels,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "111",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/YFZlJtc.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "112",
   "metadata": {},
   "source": [
    "#### feature_histogram"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "113",
   "metadata": {},
   "outputs": [],
   "source": [
    "source = ee.ImageCollection(\"OREGONSTATE/PRISM/Norm91m\").toBands()\n",
    "region = ee.Geometry.Rectangle(-123.41, 40.43, -116.38, 45.14)\n",
    "features = source.sample(region, 5000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "114",
   "metadata": {},
   "outputs": [],
   "source": [
    "geemap.ee_to_df(features.limit(5).select([\"07_ppt\"]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "115",
   "metadata": {},
   "outputs": [],
   "source": [
    "property = \"07_ppt\"\n",
    "title = \"July Precipitation Distribution for NW USA\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "116",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.feature_histogram(\n",
    "    features,\n",
    "    property,\n",
    "    max_buckets=None,\n",
    "    title=title,\n",
    "    x_label=\"Precipitation (mm)\",\n",
    "    y_label=\"Pixel Count\",\n",
    "    colors=[\"#1d6b99\"],\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "117",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/ErIp7Oy.png)\n",
    "\n",
    "### Image charts\n",
    "\n",
    "#### image_by_region"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "118",
   "metadata": {},
   "outputs": [],
   "source": [
    "ecoregions = ee.FeatureCollection(\"projects/google/charts_feature_example\")\n",
    "image = (\n",
    "    ee.ImageCollection(\"OREGONSTATE/PRISM/Norm91m\").toBands().select(\"[0-9][0-9]_tmean\")\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "119",
   "metadata": {},
   "outputs": [],
   "source": [
    "labels = calendar.month_abbr[1:]  # a list of month labels, e.g. ['Jan', 'Feb', ...]\n",
    "title = \"Average Monthly Temperature by Ecoregion\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "120",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.image_by_region(\n",
    "    image,\n",
    "    ecoregions,\n",
    "    reducer=\"mean\",\n",
    "    scale=500,\n",
    "    x_property=\"label\",\n",
    "    title=title,\n",
    "    x_label=\"Ecoregion\",\n",
    "    y_label=\"Temperature\",\n",
    "    labels=labels,\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "121",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/y4rp3dK.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "122",
   "metadata": {},
   "source": [
    "#### image_regions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "123",
   "metadata": {},
   "outputs": [],
   "source": [
    "ecoregions = ee.FeatureCollection(\"projects/google/charts_feature_example\")\n",
    "image = (\n",
    "    ee.ImageCollection(\"OREGONSTATE/PRISM/Norm91m\").toBands().select(\"[0-9][0-9]_ppt\")\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "124",
   "metadata": {},
   "outputs": [],
   "source": [
    "keys = [str(x).zfill(2) + \"_ppt\" for x in range(1, 13)]\n",
    "values = calendar.month_abbr[1:]  # a list of month labels, e.g. ['Jan', 'Feb', ...]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "125",
   "metadata": {},
   "outputs": [],
   "source": [
    "x_properties = dict(zip(keys, values))\n",
    "title = \"Average Ecoregion Precipitation by Month\"\n",
    "colors = [\"#f0af07\", \"#0f8755\", \"#76b349\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "126",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.image_regions(\n",
    "    image,\n",
    "    ecoregions,\n",
    "    reducer=\"mean\",\n",
    "    scale=500,\n",
    "    series_property=\"label\",\n",
    "    x_labels=x_properties,\n",
    "    title=title,\n",
    "    colors=colors,\n",
    "    x_label=\"Month\",\n",
    "    y_label=\"Precipitation (mm)\",\n",
    "    legend_location=\"top-left\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "127",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/5WJVCNY.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "128",
   "metadata": {},
   "source": [
    "#### image_by_class"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "129",
   "metadata": {},
   "outputs": [],
   "source": [
    "ecoregions = ee.FeatureCollection(\"projects/google/charts_feature_example\")\n",
    "\n",
    "image = (\n",
    "    ee.ImageCollection(\"MODIS/061/MOD09A1\")\n",
    "    .filter(ee.Filter.date(\"2018-06-01\", \"2018-09-01\"))\n",
    "    .select(\"sur_refl_b0[0-7]\")\n",
    "    .mean()\n",
    "    .select([2, 3, 0, 1, 4, 5, 6])\n",
    ")\n",
    "\n",
    "wavelengths = [469, 555, 655, 858, 1240, 1640, 2130]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "130",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.image_by_class(\n",
    "    image,\n",
    "    class_band=\"label\",\n",
    "    region=ecoregions,\n",
    "    reducer=\"MEAN\",\n",
    "    scale=500,\n",
    "    x_labels=wavelengths,\n",
    "    title=\"Ecoregion Spectral Signatures\",\n",
    "    x_label=\"Wavelength (nm)\",\n",
    "    y_label=\"Reflectance (x1e4)\",\n",
    "    colors=[\"#f0af07\", \"#0f8755\", \"#76b349\"],\n",
    "    legend_location=\"top-left\",\n",
    "    interpolation=\"basis\",\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "131",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/XqYHvBV.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "132",
   "metadata": {},
   "source": [
    "#### image_histogram"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "133",
   "metadata": {},
   "outputs": [],
   "source": [
    "image = (\n",
    "    ee.ImageCollection(\"MODIS/061/MOD09A1\")\n",
    "    .filter(ee.Filter.date(\"2018-06-01\", \"2018-09-01\"))\n",
    "    .select([\"sur_refl_b01\", \"sur_refl_b02\", \"sur_refl_b06\"])\n",
    "    .mean()\n",
    ")\n",
    "\n",
    "region = ee.Geometry.Rectangle([-112.60, 40.60, -111.18, 41.22])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "134",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.image_histogram(\n",
    "    image,\n",
    "    region,\n",
    "    scale=500,\n",
    "    max_buckets=200,\n",
    "    min_bucket_width=1.0,\n",
    "    max_raw=1000,\n",
    "    max_pixels=int(1e6),\n",
    "    title=\"MODIS SR Reflectance Histogram\",\n",
    "    labels=[\"Red\", \"NIR\", \"SWIR\"],\n",
    "    colors=[\"#cf513e\", \"#1d6b99\", \"#f0af07\"],\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "135",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/mY4yoYH.png)\n",
    "\n",
    "### ImageCollection charts\n",
    "\n",
    "#### image_series"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "136",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the forest feature collection.\n",
    "forest = ee.FeatureCollection(\"projects/google/charts_feature_example\").filter(\n",
    "    ee.Filter.eq(\"label\", \"Forest\")\n",
    ")\n",
    "\n",
    "# Load MODIS vegetation indices data and subset a decade of images.\n",
    "veg_indices = (\n",
    "    ee.ImageCollection(\"MODIS/061/MOD13A1\")\n",
    "    .filter(ee.Filter.date(\"2010-01-01\", \"2020-01-01\"))\n",
    "    .select([\"NDVI\", \"EVI\"])\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "137",
   "metadata": {},
   "outputs": [],
   "source": [
    "title = \"Average Vegetation Index Value by Date for Forest\"\n",
    "x_label = \"Year\"\n",
    "y_label = \"Vegetation index (x1e4)\"\n",
    "colors = [\"#e37d05\", \"#1d6b99\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "138",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.image_series(\n",
    "    veg_indices,\n",
    "    region=forest,\n",
    "    reducer=ee.Reducer.mean(),\n",
    "    scale=500,\n",
    "    x_property=\"system:time_start\",\n",
    "    chart_type=\"LineChart\",\n",
    "    x_cols=\"date\",\n",
    "    y_cols=[\"NDVI\", \"EVI\"],\n",
    "    colors=colors,\n",
    "    title=title,\n",
    "    x_label=x_label,\n",
    "    y_label=y_label,\n",
    "    legend_location=\"right\",\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "139",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/r9zSJh6.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "140",
   "metadata": {},
   "source": [
    "#### image_series_by_region"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "141",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the example feature collection.\n",
    "ecoregions = ee.FeatureCollection(\"projects/google/charts_feature_example\")\n",
    "\n",
    "# Load MODIS vegetation indices data and subset a decade of images.\n",
    "veg_indices = (\n",
    "    ee.ImageCollection(\"MODIS/061/MOD13A1\")\n",
    "    .filter(ee.Filter.date(\"2010-01-01\", \"2020-01-01\"))\n",
    "    .select([\"NDVI\"])\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "142",
   "metadata": {},
   "outputs": [],
   "source": [
    "title = \"Average NDVI Value by Date\"\n",
    "x_label = \"Date\"\n",
    "y_label = \"NDVI (x1e4)\"\n",
    "x_cols = \"index\"\n",
    "y_cols = [\"Desert\", \"Forest\", \"Grassland\"]\n",
    "colors = [\"#f0af07\", \"#0f8755\", \"#76b349\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "143",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.image_series_by_region(\n",
    "    veg_indices,\n",
    "    regions=ecoregions,\n",
    "    reducer=ee.Reducer.mean(),\n",
    "    band=\"NDVI\",\n",
    "    scale=500,\n",
    "    x_property=\"system:time_start\",\n",
    "    series_property=\"label\",\n",
    "    chart_type=\"LineChart\",\n",
    "    x_cols=x_cols,\n",
    "    y_cols=y_cols,\n",
    "    title=title,\n",
    "    x_label=x_label,\n",
    "    y_label=y_label,\n",
    "    colors=colors,\n",
    "    stroke_width=3,\n",
    "    legend_location=\"bottom-left\",\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "144",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/rnILSfI.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "145",
   "metadata": {},
   "source": [
    "#### image_doy_series"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "146",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the example feature collection and subset the grassland feature.\n",
    "grassland = ee.FeatureCollection(\"projects/google/charts_feature_example\").filter(\n",
    "    ee.Filter.eq(\"label\", \"Grassland\")\n",
    ")\n",
    "\n",
    "# Load MODIS vegetation indices data and subset a decade of images.\n",
    "veg_indices = (\n",
    "    ee.ImageCollection(\"MODIS/061/MOD13A1\")\n",
    "    .filter(ee.Filter.date(\"2010-01-01\", \"2020-01-01\"))\n",
    "    .select([\"NDVI\", \"EVI\"])\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "147",
   "metadata": {},
   "outputs": [],
   "source": [
    "title = \"Average Vegetation Index Value by Day of Year for Grassland\"\n",
    "x_label = \"Day of Year\"\n",
    "y_label = \"Vegetation Index (x1e4)\"\n",
    "colors = [\"#f0af07\", \"#0f8755\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "148",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.image_doy_series(\n",
    "    image_collection=veg_indices,\n",
    "    region=grassland,\n",
    "    scale=500,\n",
    "    chart_type=\"LineChart\",\n",
    "    title=title,\n",
    "    x_label=x_label,\n",
    "    y_label=y_label,\n",
    "    colors=colors,\n",
    "    stroke_width=5,\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "149",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/F0z088e.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "150",
   "metadata": {},
   "source": [
    "#### image_doy_series_by_year"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "151",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the example feature collection and subset the grassland feature.\n",
    "grassland = ee.FeatureCollection(\"projects/google/charts_feature_example\").filter(\n",
    "    ee.Filter.eq(\"label\", \"Grassland\")\n",
    ")\n",
    "\n",
    "# Load MODIS vegetation indices data and subset years 2012 and 2019.\n",
    "veg_indices = (\n",
    "    ee.ImageCollection(\"MODIS/061/MOD13A1\")\n",
    "    .filter(\n",
    "        ee.Filter.Or(\n",
    "            ee.Filter.date(\"2012-01-01\", \"2013-01-01\"),\n",
    "            ee.Filter.date(\"2019-01-01\", \"2020-01-01\"),\n",
    "        )\n",
    "    )\n",
    "    .select([\"NDVI\", \"EVI\"])\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "152",
   "metadata": {},
   "outputs": [],
   "source": [
    "title = \"Average Vegetation Index Value by Day of Year for Grassland\"\n",
    "x_label = \"Day of Year\"\n",
    "y_label = \"Vegetation Index (x1e4)\"\n",
    "colors = [\"#e37d05\", \"#1d6b99\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "153",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.doy_series_by_year(\n",
    "    veg_indices,\n",
    "    band_name=\"NDVI\",\n",
    "    region=grassland,\n",
    "    scale=500,\n",
    "    chart_type=\"LineChart\",\n",
    "    colors=colors,\n",
    "    title=title,\n",
    "    x_label=x_label,\n",
    "    y_label=y_label,\n",
    "    stroke_width=5,\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "154",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/ui6zpbl.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "155",
   "metadata": {},
   "source": [
    "#### image_doy_series_by_region"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "156",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the example feature collection and subset the grassland feature.\n",
    "ecoregions = ee.FeatureCollection(\"projects/google/charts_feature_example\")\n",
    "\n",
    "# Load MODIS vegetation indices data and subset a decade of images.\n",
    "veg_indices = (\n",
    "    ee.ImageCollection(\"MODIS/061/MOD13A1\")\n",
    "    .filter(ee.Filter.date(\"2010-01-01\", \"2020-01-01\"))\n",
    "    .select([\"NDVI\"])\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "157",
   "metadata": {},
   "outputs": [],
   "source": [
    "title = \"Average Vegetation Index Value by Day of Year for Grassland\"\n",
    "x_label = \"Day of Year\"\n",
    "y_label = \"Vegetation Index (x1e4)\"\n",
    "colors = [\"#f0af07\", \"#0f8755\", \"#76b349\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "158",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.image_doy_series_by_region(\n",
    "    veg_indices,\n",
    "    \"NDVI\",\n",
    "    ecoregions,\n",
    "    region_reducer=\"mean\",\n",
    "    scale=500,\n",
    "    year_reducer=ee.Reducer.mean(),\n",
    "    start_day=1,\n",
    "    end_day=366,\n",
    "    series_property=\"label\",\n",
    "    stroke_width=5,\n",
    "    chart_type=\"LineChart\",\n",
    "    title=title,\n",
    "    x_label=x_label,\n",
    "    y_label=y_label,\n",
    "    colors=colors,\n",
    "    legend_location=\"right\",\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "159",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/eGqGoRs.png)\n",
    "\n",
    "### Array and list charts\n",
    "\n",
    "#### Scatter plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "160",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the example feature collection and subset the forest feature.\n",
    "forest = ee.FeatureCollection(\"projects/google/charts_feature_example\").filter(\n",
    "    ee.Filter.eq(\"label\", \"Forest\")\n",
    ")\n",
    "\n",
    "# Define a MODIS surface reflectance composite.\n",
    "modisSr = (\n",
    "    ee.ImageCollection(\"MODIS/061/MOD09A1\")\n",
    "    .filter(ee.Filter.date(\"2018-06-01\", \"2018-09-01\"))\n",
    "    .select(\"sur_refl_b0[0-7]\")\n",
    "    .mean()\n",
    ")\n",
    "\n",
    "# Reduce MODIS reflectance bands by forest region; get a dictionary with\n",
    "# band names as keys, pixel values as lists.\n",
    "pixel_vals = modisSr.reduceRegion(\n",
    "    **{\"reducer\": ee.Reducer.toList(), \"geometry\": forest.geometry(), \"scale\": 2000}\n",
    ")\n",
    "\n",
    "# Convert NIR and SWIR value lists to an array to be plotted along the y-axis.\n",
    "y_values = pixel_vals.toArray([\"sur_refl_b02\", \"sur_refl_b06\"])\n",
    "\n",
    "\n",
    "# Get the red band value list; to be plotted along the x-axis.\n",
    "x_values = ee.List(pixel_vals.get(\"sur_refl_b01\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "161",
   "metadata": {},
   "outputs": [],
   "source": [
    "title = \"Relationship Among Spectral Bands for Forest Pixels\"\n",
    "colors = [\"rgba(29,107,153,0.4)\", \"rgba(207,81,62,0.4)\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "162",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.array_values(\n",
    "    y_values,\n",
    "    axis=1,\n",
    "    x_labels=x_values,\n",
    "    series_names=[\"NIR\", \"SWIR\"],\n",
    "    chart_type=\"ScatterChart\",\n",
    "    colors=colors,\n",
    "    title=title,\n",
    "    x_label=\"Red reflectance (x1e4)\",\n",
    "    y_label=\"NIR & SWIR reflectance (x1e4)\",\n",
    "    default_size=15,\n",
    "    xlim=(0, 800),\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "163",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/zkPlZIO.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "164",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = ee.List(pixel_vals.get(\"sur_refl_b01\"))\n",
    "y = ee.List(pixel_vals.get(\"sur_refl_b06\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "165",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.array_values(\n",
    "    y,\n",
    "    x_labels=x,\n",
    "    series_names=[\"SWIR\"],\n",
    "    chart_type=\"ScatterChart\",\n",
    "    colors=[\"rgba(207,81,62,0.4)\"],\n",
    "    title=title,\n",
    "    x_label=\"Red reflectance (x1e4)\",\n",
    "    y_label=\"SWIR reflectance (x1e4)\",\n",
    "    default_size=15,\n",
    "    xlim=(0, 800),\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "166",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/WHUHjH6.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "167",
   "metadata": {},
   "source": [
    " #### Transect line plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "168",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define a line across the Olympic Peninsula, USA.\n",
    "transect = ee.Geometry.LineString([[-122.8, 47.8], [-124.5, 47.8]])\n",
    "\n",
    "# Define a pixel coordinate image.\n",
    "lat_lon_img = ee.Image.pixelLonLat()\n",
    "\n",
    "# Import a digital surface model and add latitude and longitude bands.\n",
    "elev_img = ee.Image(\"USGS/SRTMGL1_003\").select(\"elevation\").addBands(lat_lon_img)\n",
    "\n",
    "# Reduce elevation and coordinate bands by transect line; get a dictionary with\n",
    "# band names as keys, pixel values as lists.\n",
    "elev_transect = elev_img.reduceRegion(\n",
    "    reducer=ee.Reducer.toList(),\n",
    "    geometry=transect,\n",
    "    scale=1000,\n",
    ")\n",
    "\n",
    "# Get longitude and elevation value lists from the reduction dictionary.\n",
    "lon = ee.List(elev_transect.get(\"longitude\"))\n",
    "elev = ee.List(elev_transect.get(\"elevation\"))\n",
    "\n",
    "# Sort the longitude and elevation values by ascending longitude.\n",
    "lon_sort = lon.sort(lon)\n",
    "elev_sort = elev.sort(lon)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "169",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.array_values(\n",
    "    elev_sort,\n",
    "    x_labels=lon_sort,\n",
    "    series_names=[\"Elevation\"],\n",
    "    chart_type=\"AreaChart\",\n",
    "    colors=[\"#1d6b99\"],\n",
    "    title=\"Elevation Profile Across Longitude\",\n",
    "    x_label=\"Longitude\",\n",
    "    y_label=\"Elevation (m)\",\n",
    "    stroke_width=5,\n",
    "    fill=\"bottom\",\n",
    "    fill_opacities=[0.4],\n",
    "    ylim=(0, 2500),\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "170",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/k3XRita.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "171",
   "metadata": {},
   "source": [
    "#### Metadata scatter plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "172",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import a Landsat 8 collection and filter to a single path/row.\n",
    "col = ee.ImageCollection(\"LANDSAT/LC08/C02/T1_L2\").filter(\n",
    "    ee.Filter.expression(\"WRS_PATH ==  45 && WRS_ROW == 30\")\n",
    ")\n",
    "\n",
    "# Reduce image properties to a series of lists; one for each selected property.\n",
    "propVals = col.reduceColumns(\n",
    "    reducer=ee.Reducer.toList().repeat(2),\n",
    "    selectors=[\"CLOUD_COVER\", \"GEOMETRIC_RMSE_MODEL\"],\n",
    ").get(\"list\")\n",
    "\n",
    "# Get selected image property value lists; to be plotted along x and y axes.\n",
    "x = ee.List(ee.List(propVals).get(0))\n",
    "y = ee.List(ee.List(propVals).get(1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "173",
   "metadata": {},
   "outputs": [],
   "source": [
    "colors = [geemap.hex_to_rgba(\"#96356f\", 0.4)]\n",
    "print(colors)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "174",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.array_values(\n",
    "    y,\n",
    "    x_labels=x,\n",
    "    series_names=[\"RMSE\"],\n",
    "    chart_type=\"ScatterChart\",\n",
    "    colors=colors,\n",
    "    title=\"Landsat 8 Image Collection Metadata (045030)\",\n",
    "    x_label=\"Cloud cover (%)\",\n",
    "    y_label=\"Geometric RMSE (m)\",\n",
    "    default_size=15,\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "175",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/3COY3xd.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "176",
   "metadata": {},
   "source": [
    "#### Mapped function scatter & line plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "177",
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "\n",
    "start = -2 * math.pi\n",
    "end = 2 * math.pi\n",
    "points = ee.List.sequence(start, end, None, 50)\n",
    "\n",
    "\n",
    "def sin_func(val):\n",
    "    return ee.Number(val).sin()\n",
    "\n",
    "\n",
    "values = points.map(sin_func)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "178",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.array_values(\n",
    "    values,\n",
    "    points,\n",
    "    chart_type=\"LineChart\",\n",
    "    colors=[\"#39a8a7\"],\n",
    "    title=\"Sine Function\",\n",
    "    x_label=\"radians\",\n",
    "    y_label=\"sin(x)\",\n",
    "    marker=\"circle\",\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "179",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/7qcxvey.png)\n",
    "\n",
    "### Data table charts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "180",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "181",
   "metadata": {},
   "source": [
    "#### Manual DataTable chart"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "182",
   "metadata": {},
   "outputs": [],
   "source": [
    "data = {\n",
    "    \"State\": [\"CA\", \"NY\", \"IL\", \"MI\", \"OR\"],\n",
    "    \"Population\": [37253956, 19378102, 12830632, 9883640, 3831074],\n",
    "}\n",
    "\n",
    "df = pd.DataFrame(data)\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "183",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.Chart(\n",
    "    df,\n",
    "    x_cols=[\"State\"],\n",
    "    y_cols=[\"Population\"],\n",
    "    chart_type=\"ColumnChart\",\n",
    "    colors=[\"#1d6b99\"],\n",
    "    title=\"State Population (US census, 2010)\",\n",
    "    x_label=\"State\",\n",
    "    y_label=\"Population\",\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "184",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/vuxNmuh.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "185",
   "metadata": {},
   "source": [
    "#### Computed DataTable chart"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "186",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the example feature collection and subset the forest feature.\n",
    "forest = ee.FeatureCollection(\"projects/google/charts_feature_example\").filter(\n",
    "    ee.Filter.eq(\"label\", \"Forest\")\n",
    ")\n",
    "\n",
    "# Load MODIS vegetation indices data and subset a decade of images.\n",
    "veg_indices = (\n",
    "    ee.ImageCollection(\"MODIS/061/MOD13A1\")\n",
    "    .filter(ee.Filter.date(\"2010-01-01\", \"2020-01-01\"))\n",
    "    .select([\"NDVI\", \"EVI\"])\n",
    ")\n",
    "\n",
    "# Build a feature collection where each feature has a property that represents\n",
    "# a DataFrame row.\n",
    "\n",
    "\n",
    "def aggregate(img):\n",
    "    # Reduce the image to the mean of pixels intersecting the forest ecoregion.\n",
    "    stat = img.reduceRegion(\n",
    "        **{\"reducer\": ee.Reducer.mean(), \"geometry\": forest, \"scale\": 500}\n",
    "    )\n",
    "\n",
    "    # Extract the reduction results along with the image date.\n",
    "    date = geemap.image_date(img)\n",
    "    evi = stat.get(\"EVI\")\n",
    "    ndvi = stat.get(\"NDVI\")\n",
    "\n",
    "    # Make a list of observation attributes to define a row in the DataTable.\n",
    "    row = ee.List([date, evi, ndvi])\n",
    "\n",
    "    # Return the row as a property of an ee.Feature.\n",
    "    return ee.Feature(None, {\"row\": row})\n",
    "\n",
    "\n",
    "reduction_table = veg_indices.map(aggregate)\n",
    "\n",
    "# Aggregate the 'row' property from all features in the new feature collection\n",
    "# to make a server-side 2-D list (DataTable).\n",
    "data_table_server = reduction_table.aggregate_array(\"row\")\n",
    "\n",
    "# Define column names and properties for the DataTable. The order should\n",
    "# correspond to the order in the construction of the 'row' property above.\n",
    "column_header = ee.List([[\"Date\", \"EVI\", \"NDVI\"]])\n",
    "\n",
    "# Concatenate the column header to the table.\n",
    "data_table_server = column_header.cat(data_table_server)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "187",
   "metadata": {},
   "outputs": [],
   "source": [
    "data_table = chart.DataTable(data_table_server, date_column=\"Date\")\n",
    "data_table.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "188",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.Chart(\n",
    "    data_table,\n",
    "    chart_type=\"LineChart\",\n",
    "    x_cols=\"Date\",\n",
    "    y_cols=[\"EVI\", \"NDVI\"],\n",
    "    colors=[\"#e37d05\", \"#1d6b99\"],\n",
    "    title=\"Average Vegetation Index Value by Date for Forest\",\n",
    "    x_label=\"Date\",\n",
    "    y_label=\"Vegetation index (x1e4)\",\n",
    "    stroke_width=3,\n",
    "    legend_location=\"right\",\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "189",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/PWei7QC.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "190",
   "metadata": {},
   "source": [
    "#### Interval chart"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "191",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define a point to extract an NDVI time series for.\n",
    "geometry = ee.Geometry.Point([-121.679, 36.479])\n",
    "\n",
    "# Define a band of interest (NDVI), import the MODIS vegetation index dataset,\n",
    "# and select the band.\n",
    "band = \"NDVI\"\n",
    "ndvi_col = ee.ImageCollection(\"MODIS/061/MOD13Q1\").select(band)\n",
    "\n",
    "# Map over the collection to add a day of year (doy) property to each image.\n",
    "\n",
    "\n",
    "def set_doy(img):\n",
    "    doy = ee.Date(img.get(\"system:time_start\")).getRelative(\"day\", \"year\")\n",
    "    # Add 8 to day of year number so that the doy label represents the middle of\n",
    "    # the 16-day MODIS NDVI composite.\n",
    "    return img.set(\"doy\", ee.Number(doy).add(8))\n",
    "\n",
    "\n",
    "ndvi_col = ndvi_col.map(set_doy)\n",
    "\n",
    "# Join all coincident day of year observations into a set of image collections.\n",
    "distinct_doy = ndvi_col.filterDate(\"2013-01-01\", \"2014-01-01\")\n",
    "filter = ee.Filter.equals(**{\"leftField\": \"doy\", \"rightField\": \"doy\"})\n",
    "join = ee.Join.saveAll(\"doy_matches\")\n",
    "join_col = ee.ImageCollection(join.apply(distinct_doy, ndvi_col, filter))\n",
    "\n",
    "# Calculate the absolute range, interquartile range, and median for the set\n",
    "# of images composing each coincident doy observation group. The result is\n",
    "# an image collection with an image representative per unique doy observation\n",
    "# with bands that describe the 0, 25, 50, 75, 100 percentiles for the set of\n",
    "# coincident doy images.\n",
    "\n",
    "\n",
    "def cal_percentiles(img):\n",
    "    doyCol = ee.ImageCollection.fromImages(img.get(\"doy_matches\"))\n",
    "\n",
    "    return doyCol.reduce(\n",
    "        ee.Reducer.percentile([0, 25, 50, 75, 100], [\"p0\", \"p25\", \"p50\", \"p75\", \"p100\"])\n",
    "    ).set({\"doy\": img.get(\"doy\")})\n",
    "\n",
    "\n",
    "comp = ee.ImageCollection(join_col.map(cal_percentiles))\n",
    "\n",
    "# Extract the inter-annual NDVI doy percentile statistics for the\n",
    "# point of interest per unique doy representative. The result is\n",
    "# is a feature collection where each feature is a doy representative that\n",
    "# contains a property (row) describing the respective inter-annual NDVI\n",
    "# variance, formatted as a list of values.\n",
    "\n",
    "\n",
    "def order_percentiles(img):\n",
    "    stats = ee.Dictionary(\n",
    "        img.reduceRegion(\n",
    "            **{\"reducer\": ee.Reducer.first(), \"geometry\": geometry, \"scale\": 250}\n",
    "        )\n",
    "    )\n",
    "\n",
    "    # Order the percentile reduction elements according to how you want columns\n",
    "    # in the DataTable arranged (x-axis values need to be first).\n",
    "    row = ee.List(\n",
    "        [\n",
    "            img.get(\"doy\"),\n",
    "            stats.get(band + \"_p50\"),\n",
    "            stats.get(band + \"_p0\"),\n",
    "            stats.get(band + \"_p25\"),\n",
    "            stats.get(band + \"_p75\"),\n",
    "            stats.get(band + \"_p100\"),\n",
    "        ]\n",
    "    )\n",
    "\n",
    "    # Return the row as a property of an ee.Feature.\n",
    "    return ee.Feature(None, {\"row\": row})\n",
    "\n",
    "\n",
    "reduction_table = comp.map(order_percentiles)\n",
    "\n",
    "# Aggregate the 'row' properties to make a server-side 2-D array (DataTable).\n",
    "data_table_server = reduction_table.aggregate_array(\"row\")\n",
    "\n",
    "# Define column names and properties for the DataTable. The order should\n",
    "# correspond to the order in the construction of the 'row' property above.\n",
    "column_header = ee.List([[\"DOY\", \"median\", \"p0\", \"p25\", \"p75\", \"p100\"]])\n",
    "\n",
    "# Concatenate the column header to the table.\n",
    "data_table_server = column_header.cat(data_table_server)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "192",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = chart.DataTable(data_table_server)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "193",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = chart.Chart(\n",
    "    df,\n",
    "    chart_type=\"IntervalChart\",\n",
    "    x_cols=\"DOY\",\n",
    "    y_cols=[\"p0\", \"p25\", \"median\", \"p75\", \"p100\"],\n",
    "    title=\"Annual NDVI Time Series with Inter-Annual Variance\",\n",
    "    x_label=\"Day of Year\",\n",
    "    y_label=\"Vegetation index (x1e4)\",\n",
    "    stroke_width=1,\n",
    "    fill=\"between\",\n",
    "    fill_colors=[\"#b6d1c6\", \"#83b191\", \"#83b191\", \"#b6d1c6\"],\n",
    "    fill_opacities=[0.6] * 4,\n",
    "    labels=[\"p0\", \"p25\", \"median\", \"p75\", \"p100\"],\n",
    "    display_legend=True,\n",
    "    legend_location=\"top-right\",\n",
    "    ylim=(0, 10000),\n",
    ")\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "194",
   "metadata": {},
   "source": [
    "![](https://i.imgur.com/i8ZrGPR.png)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
